I ended up deciding to write an AsyncSequence wrapper. If it helps anyone else, then it looks like this in its current state, but changes will happen. I might release it as a Swift package in the future, so I can reuse it later
import Foundation
class BonjourBrowser: NSObject, NetServiceDelegate {
typealias ServiceFunction = (NetService) -> ()
private let delegate: Delegate = Delegate()
private let browser: NetServiceBrowser = NetServiceBrowser()
private var foundService: (ServiceFunction)?
private class Delegate : NSObject, NetServiceBrowserDelegate {
unowned var browser: BonjourBrowser?
override init() {
super.init()
}
func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
self.browser?.didFind(serivce: service)
}
}
init(type: String) {
super.init()
delegate.browser = self
browser.delegate = delegate
browser.searchForServices(ofType: type, inDomain: "local.")
}
fileprivate func didFind(serivce: NetService) {
foundService?(serivce)
}
func didFindService() -> AsyncStream<NetService> {
AsyncStream { continuation in
foundService = { service in
service.delegate = self
service.resolve(withTimeout: 5.0)
continuation.yield(service)
}
}
}
func netServiceDidResolveAddress(_ sender: NetService) {
print(sender.hostName)
}
func netService(_ sender: NetService, didNotResolve errorDict: [String: NSNumber]) {
let code = (errorDict[NetService.errorCode]?.intValue)
.flatMap { NetService.ErrorCode.init(rawValue: $0) }
?? .unknownError
let error = NSError(domain: NetService.errorDomain, code: code.rawValue, userInfo: nil)
print(error)
}
}